Repository navigation
Support pandas 3+ in the dataframes API (#40709) - #40768
dhanusharer wants to merge 4 commits into
Conversation
* Enable pandas 3.x dependency on Python 3.11+ via PEP 508 environment markers * Update tox.ini and Gradle build configs to test pandas 3.0 in py311 * Add defensive attribute checking in frame_base decorators (args_to_kwargs, populate_defaults, with_docs_from) * Support pandas 3.0 Copy-on-Write defaults * Update fillna, groupby, first, last, and applymap to handle removed pandas 3.0 arguments and methods * Add pandas 3.0 string and datetime dtype recognition in pandas_type_compatibility * Update frames_test.py to support pandas 3.0
There was a problem hiding this comment.
📋 Review Summary
This PR updates the DataFrame API, schema conversion utilities, and type compatibility test suites to support Pandas 3.0 (where infer_string is enabled by default) and adds py311-pandas-30 to tox.ini. While the core Pandas 3.0 compatibility fixes are solid, the setup.py package bounds and Gradle test tasks are not updated yet, and one schema conversion path still relies on dtype.kind == 'O' instead of pd.api.types.is_string_dtype.
🔍 General Feedback
- Dependency & CI Wiring (
setup.py&build.gradle):sdks/python/setup.pystill capsdataframe_dependencyat'pandas>=2.2.2,<2.4'(with# TODO(https://github.com/apache/beam/issues/40709): support pandas 3+) anddocs/testextras at'pandas<2.6.0'. Additionally,sdks/python/test-suites/tox/py311/build.gradleneeds atestPy311pandas-30task registered so the newpy311-pandas-30tox environment is actually executed inpostCommitPyDep(and.github/trigger_files/beam_PostCommit_Python_Dependency.jsoncan be bumped to trigger it on the PR). - Remaining
dtype.kind == 'O'check inschemas.py:sdks/python/apache_beam/dataframe/schemas.py(line 206 inelement_type_from_dataframe) still checksif dtype.kind == 'O': return Anywhen inferring schema types from a proxy withoutelement_type. Under Pandas 3.0, default string columns havepd.StringDtype(na_value=np.nan)(dtype.kind == 'U'), which bypasses that branch and falls through todtype_to_fieldtype(raisingTypeError: Unable to encounter corresponding Beam type for dtype=str). Updating that check toif dtype.kind == 'O' or pd.api.types.is_string_dtype(dtype):(or handlingpd.api.types.is_string_dtypeinpandas_type_compatibility.py) will keep string column fallback consistent.
💡 Tip: Comment /gemini review on this pull request to trigger a new Gemini code review.
💬 Inline Findings
sdks/python/tox.ini(line 376): 🟠 High:py311-pandas-30is added here intox.ini, but two other places need to be updated in tandem:
sdks/python/test-suites/tox/py311/build.gradleneeds a correspondingtoxTask "testPy311pandas-30", "py311-pandas-30", "${posargs}"(added totestandpostCommitPyDep) so that CI actually runs this tox environment.sdks/python/setup.pystill restrictsdataframe_dependencyto'pandas>=2.2.2,<2.4'(anddocs/testextras to'pandas<2.6.0'). Since tox installs the package withextras = test,dataframe,..., pip will either report a version conflict incommands_pre(pip check) or prevent users from installing Pandas 3.0 withapache-beam[dataframe].
sdks/python/apache_beam/dataframe/schemas_test.py(line 227): 🟡 Medium: Whenmajor >= 3,series_testsis reassigned instead of appended to (+=), which drops all the numeric and nullable integer Series test cases defined in lines 211–218 on Pandas 3+.
series_tests += [(pd.Series(['a', 'b', 'c'], dtype=dtype), str)]
…commit dependency CI
|
/gemini review |
|
Assigning reviewers: R: @claudevdm for label python. This pull request likely touches a core component ("core" label). Please review with scrutiny. Note: If you would like to opt out of this review, comment Available commands:
The PR bot will only process comments in the main thread (not review comments). |
claudevdm
left a comment
There was a problem hiding this comment.
This changes the pandas version for every Python 3.11+ user of the dataframe extra and for every Python 3.11+ precommit. Through the weekly dependency update, it also changes the default containers, which carry users' own pandas code too. That's a large blast radius, so I think we should scope it out before raising the cap, as #40709 asks.
Here is a potential approach:
- List what changed in pandas. Go through the 3.0 and 3.1 release notes (breaking changes, removed deprecations, changed defaults). Write down each item that could reach Beam.
- List where Beam depends on pandas. That means:
- the DataFrame API, which wraps pandas methods by name and signature;
- conversion between dtypes and Beam schemas;
- DataFrame IO;
- other modules that use pandas (CSV IO, YAML, interactive, ML handlers);
- the default containers.
- Match the two lists up and decide the behaviour. For each change that reaches Beam, decide whether Beam follows pandas 3, keeps the old behaviour, or marks it unsupported. The changes that alter results without raising an error need an explicit decision, not just a fix. Examples are the new string dtype, copy-on-write, and changed defaults.
- Start on pandas 2.3. pandas 2.3 can switch on the pandas 3 string dtype (
future.infer_string) and copy-on-write (mode.copy_on_write), and it warns about features pandas 3 removes. Run Beam's tests with those switched on and warnings treated as errors. That finds many problems while the cap stays where it is. - Test every version the cap allows. Run the full tests, including the pandas doctest suite, on both ends of the supported 2.x range and on each 3.x minor version. Group the failures by cause rather than by test.
- Look for what the tests miss.
- Compare Beam's results with pandas' on the same inputs, across argument combinations, not just the defaults.
- Use a script to compare the signatures of wrapped methods between pandas versions.
- Run each dtype through a real pipeline (
to_dataframe→to_pcollection) and check the output types and missing values. - Check that every version-specific branch actually runs on that version.
- Check rollout cases.
- Launcher and workers on different pandas versions.
- Pipeline update compatibility where output schemas change.
- What the default containers ship, and when.
The result could be a short write-up on #40709 listing:
- each breaking change and the decision for it;
- the remaining work;
- the rollout plan.
A low-risk rollout would be:
- Land the fixes with the cap still below 3, checking each on pandas 2.x.
- Add a CI env for each 3.x version once it passes.
- Raise the cap in a separate PR with a CHANGES.md entry.
|
Thank you for the detailed feedback! That approach makes complete sense regarding the blast radius on containers and Python 3.11+ users. I have adjusted this PR to follow Phase 1 of the proposed rollout:
I've also posted the complete scoping analysis and decision matrix on #40709. Once this preparation PR lands and Pandas 3.0 pre-releases are verified, raising the cap can follow in a separate PR with a |
…ger file conflict
Fixes #40709
Summary of Changes
pandas>=2.2.2,<3.2for Python>=3.11while preservingpandas<2.4for Python 3.10 using PEP 508 environment markers. Addedpy311-pandas-30tox environment and Gradle task.hasattr()checks inframe_base.pydecorators (@args_to_kwargs,@populate_defaults,@with_docs_from) to prevent import-time reflection crashes when pandas 3.0 removes deprecated methods or parameters. Handled permanent Copy-on-Write defaults.removed_args=['method']and avoided passingmethodtofillna()under pandas 3.0.removed_args=['axis']togroupby()and raised cleanNotImplementedErrorfor column-wise groupby.first,last, andapplymapwithhasattr()checks.fillna,first,last) withhasattr(DataFrameGroupBy, ...).method=Nonefrom_DeferredStringMethods.get_dummiesfillna call.str,pd.StringDtype, and datetime dtypes indtype_to_fieldtype().test_applymap_na_actionto skip on pandas 3.0+ and added pandas 3.0ffill/bfillbranch totest_fillna_columns.